/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.cx1.service.impl;

import com.rits.cloning.Cloner;
import org.cx1.service.impl.deprecated.RETypeService;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import org.apache.commons.lang.StringUtils;
import org.cx1.model.Amenity;
import org.cx1.model.Photo;
import org.cx1.model.ds.MockDS;
import org.cx1.model.Place;
import org.cx1.model.Listing;
import org.cx1.model.User;
import org.cx1.model.utils.KFurnishTypes;
import org.cx1.model.utils.KPlaceTypeIDs;
import org.cx1.model.utils.KPosterTypes;
import org.cx1.model.utils.ServiceResponse;
import org.cx1.model.utils.KPropertyTypeIDs;
import org.cx1.model.utils.KPropertyTypes;
import org.cx1.model.utils.KStatusTypes;
import org.cx1.model.utils.ListingComparator;
import org.cx1.model.utils.SearchOption;
import org.cx1.service.api.IAmenityService;
import org.cx1.service.api.IPlaceService;
import org.cx1.service.api.IListingService;
import org.cx1.service.api.IPhotoService;
import org.cx1.service.api.IUserService;
import org.cx1.service.utils.IDGenerator;
import org.jsoup.Jsoup;

/**
 *
 * @author ECH
 */
public class MListingService implements IListingService {

    private IUserService userService = new MUserService();
    private IPlaceService placeService = new MPlaceService();
    private IPhotoService photoService = new MPhotoService();
    private IAmenityService amenityService = new DAmenityService();
    
    private Cloner cloner = new Cloner();
    
    //CX: make sure title only spans to 65 chars
    private String trimTitle(String title) {
        String trimmed = "";
        try {
            if (title.length() > 65) {
                trimmed = title.substring(0, 65);
            }
            else {
                trimmed = title;
            }            
        } 
        catch (Exception ex) {
            System.out.println("Title- " + title);
            ex.printStackTrace();
            trimmed = "";
        }
        return trimmed;
    }
    
    @Override
    public ServiceResponse<String> create(Listing listing) {
        ServiceResponse<String> response = new ServiceResponse<String>();
        String id = null;        
        try {            
            Listing entry = new Listing();
            id = IDGenerator.generateID();
            
            entry.setId(id);            
            
            entry.setLeaseLongTerm(listing.isLeaseLongTerm());
            entry.setLeaseShortTerm(listing.isLeaseShortTerm());
            
            entry.setLongMonthRate(listing.getLongMonthRate());            
            entry.setShortDayRate(listing.getShortDayRate());
            entry.setShortWeekRate(listing.getShortWeekRate());
            entry.setShortMonthRate(listing.getShortMonthRate());
            
            entry.setPropertyTypeID(listing.getPropertyTypeID());
            entry.setStatusTypeID(listing.getStatusTypeID());
            entry.setPosterTypeID(listing.getPosterTypeID());
            entry.setFurnishTypeID(listing.getFurnishTypeID());
            
            entry.setTitle( trimTitle(listing.getTitle()) );
            entry.setDescription(cleanHtmlFragment(listing.getDescription(), "id|style"));
            entry.setNotes(listing.getNotes());
            
            entry.setAddress(listing.getAddress());
            entry.setCountry(listing.getCountry());
            entry.setRegion(listing.getRegion());
            entry.setCity(listing.getCity());
            entry.setBarangay(listing.getBarangay());
            entry.setStreet(listing.getStreet());
            entry.setStructure(listing.getStructure());
            entry.setNumber(listing.getNumber());
            entry.setFloor(listing.getFloor());
            entry.setZip(listing.getZip());
            
            entry.setLat(listing.getLat());
            entry.setLng(listing.getLng());
            
            entry.setAvailabilityDate(listing.getAvailabilityDate());
            entry.setSqArea(listing.getSqArea());
                                    
            entry.setNumBedrooms(listing.getNumBedrooms());
            entry.setNumBathrooms(listing.getNumBathrooms());
    
            entry.setLeaseStartDate(listing.getLeaseStartDate());
            entry.setLeaseEndDate(listing.getLeaseEndDate());
            entry.setExpiryDate(listing.getExpiryDate());
            
            entry.setAvailable(listing.isAvailable());
            
            entry.setAmenityIDs(listing.getAmenityIDs());
            
            //CX: defaults: not verified, not posted, available by default
            entry.setVerified(false);
            entry.setAvailable(true);
                        
            //CX: default posted
            entry.setPosted(true);
            entry.setPostDate(new Date());
            Calendar c = Calendar.getInstance();
            c.setTime(new Date());
            c.add(Calendar.DATE, 30); 
            entry.setExpiryDate(c.getTime());
            
            entry.setAmenityIDs(listing.getAmenityIDs());
            entry.setCompanyIDs(listing.getCompanyIDs());
            entry.setContactPersonIDs(listing.getContactPersonIDs());
                                                        
            ServiceResponse<String> sr1 = this.placeService.readIDByTitle(listing.getCity());
            if (sr1.isSuccessful() && !StringUtils.isEmpty(sr1.getResponse())) {
                entry.getPlaceIDs().add(sr1.getResponse());
                
                ServiceResponse<Place> sr2 = this.placeService.read(sr1.getResponse());
                Place city = sr2.getResponse();
                if (city != null) {
                    if (StringUtils.isEmpty(entry.getLat())) {
                        entry.setLat(city.getLat());
                    }
                    if (StringUtils.isEmpty(entry.getLng())) {
                        entry.setLng(city.getLng());
                    }                    
                }
            }            
            entry.getPlaceIDs().addAll(listing.getPlaceIDs());
            
            entry.setCreatorID(listing.getCreatorID());
            
            entry.setRoomoramaListing(listing.isRoomoramaListing());
            entry.setRoomorama_id(listing.getRoomorama_id());
            entry.setRoomorama_shortDayRateUSD(listing.getRoomorama_shortDayRateUSD());
            
            entry.setActive(true);
            entry.setDateCreated(new Date());
            entry.setDateModified(new Date());
                        
            MockDS.getListings().add(entry);
            
            response.setResponse(id);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response; 
    }
    
    public ServiceResponse<String> create(Listing listing, boolean verified, boolean available, boolean posted) {
        ServiceResponse<String> response = new ServiceResponse<String>();
        String id = null;        
        try {            
            Listing entry = new Listing();
            id = IDGenerator.generateID();
            
            entry.setId(id);            
            
            entry.setLeaseLongTerm(listing.isLeaseLongTerm());
            entry.setLeaseShortTerm(listing.isLeaseShortTerm());
            
            entry.setLongMonthRate(listing.getLongMonthRate());            
            entry.setShortDayRate(listing.getShortDayRate());
            entry.setShortWeekRate(listing.getShortWeekRate());
            entry.setShortMonthRate(listing.getShortMonthRate());
            
            entry.setPropertyTypeID(listing.getPropertyTypeID());
            entry.setStatusTypeID(listing.getStatusTypeID());
            entry.setPosterTypeID(listing.getPosterTypeID());
            entry.setFurnishTypeID(listing.getFurnishTypeID());
            
            entry.setTitle( trimTitle(listing.getTitle()) );
            entry.setDescription(cleanHtmlFragment(listing.getDescription(), "id|style"));
            entry.setNotes(listing.getNotes());
            
            entry.setAddress(listing.getAddress());
            entry.setCountry(listing.getCountry());
            entry.setRegion(listing.getRegion());
            entry.setCity(listing.getCity());
            entry.setBarangay(listing.getBarangay());
            entry.setStreet(listing.getStreet());
            entry.setStructure(listing.getStructure());
            entry.setNumber(listing.getNumber());
            entry.setFloor(listing.getFloor());
            entry.setZip(listing.getZip());
            
            entry.setLat(listing.getLat());
            entry.setLng(listing.getLng());
            
            entry.setAvailabilityDate(listing.getAvailabilityDate());
            entry.setSqArea(listing.getSqArea());
                                                
            entry.setNumBedrooms(listing.getNumBedrooms());
            entry.setNumBathrooms(listing.getNumBathrooms());
    
            entry.setExpiryDate(listing.getExpiryDate());
            
            //CX: default to false on first time create
            entry.setVerified(verified);
            entry.setAvailable(available);
            entry.setPosted(posted);
                        
            entry.setPlaceIDs(listing.getPlaceIDs());
            entry.setAmenityIDs(listing.getAmenityIDs());
            entry.setCompanyIDs(listing.getCompanyIDs());
            entry.setContactPersonIDs(listing.getContactPersonIDs());
                    
            entry.setCreatorID(listing.getCreatorID());
            
            entry.setPhotoIDs(listing.getPhotoIDs());  
            
            entry.setActive(true);
            entry.setDateCreated(new Date());
            entry.setDateModified(new Date());
                        
            entry.setRoomoramaListing(listing.isRoomoramaListing());
            entry.setRoomorama_id(listing.getRoomorama_id());
            entry.setRoomorama_shortDayRateUSD(listing.getRoomorama_shortDayRateUSD());
            
            MockDS.getListings().add(entry);
            
            response.setResponse(id);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response; 
    }
    
    @Override
    public ServiceResponse<Listing> read(String id) {
        ServiceResponse<Listing> response = new ServiceResponse<Listing>();
        Listing listing = null;
        try {            
            List<Listing> records = MockDS.getListings();   
            if (records != null && records.size() > 0) {
                for (Listing record : records) {
                    if (StringUtils.equalsIgnoreCase(record.getId(), id)) {
                        listing = cloneListing(record);
                        break;
                    }
                }
            }            
            populateListingAttributes(listing);            
            response.setResponse(listing);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response; 
    }

    @Override
    public ServiceResponse<Listing> readByRoomoramaID(String id) {
        ServiceResponse<Listing> response = new ServiceResponse<Listing>();
        Listing listing = null;
        try {            
            List<Listing> records = MockDS.getListings();   
            if (records != null && records.size() > 0) {
                for (Listing record : records) {
                    if (!StringUtils.isEmpty(record.getRoomorama_id()) && StringUtils.equalsIgnoreCase(record.getRoomorama_id(), id)) {
                        listing = cloneListing(record);
                        break;
                    }
                }
            }            
            populateListingAttributes(listing);            
            response.setResponse(listing);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response; 
    }
    
    @Override
    public ServiceResponse<List<Listing>> readAll(int offset, int limit) {
        ServiceResponse<List<Listing>> response = new ServiceResponse<List<Listing>>();
        List<Listing> listings = new ArrayList<Listing>();
        try {            
            List<Listing> records = MockDS.getListings();            
            if (records != null && records.size() > 0) {
                //CX: sort first
                Collections.sort(records, new ListingComparator());
                
                if (offset == 0 && limit == 0) {
                    listings.addAll(cloneListings(records));
                }
                else if (offset < records.size() && limit < records.size()) {
                    listings.addAll(cloneListings(records.subList(offset, limit)));
                }         
                else {
                     listings.addAll(cloneListings(records));
                }
            }            
            
            if (listings != null && listings.size() > 0) {
                for (Listing listing : listings) {                    
                    populateListingAttributes(listing);
                }
            }            
            response.setResponse(listings);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response; 
    }

    @Override
    public ServiceResponse<List<Listing>> readAllRoomorama(int offset, int limit) {
        ServiceResponse<List<Listing>> response = new ServiceResponse<List<Listing>>();
        List<Listing> roomoramaListings = new ArrayList<Listing>();
        List<Listing> listings = new ArrayList<Listing>();
        try {            
            List<Listing> records = MockDS.getListings();
            
            if (records != null && records.size() > 0) {
                for (Listing record : records) {
                    if (record.isRoomoramaListing()) {
                        roomoramaListings.add(record);
                    }
                }
            }
            
            if (roomoramaListings != null && roomoramaListings.size() > 0) {
                if (offset == 0 && limit == 0) {
                    listings.addAll(cloneListings(roomoramaListings));
                }
                else if (offset < roomoramaListings.size() && limit < roomoramaListings.size()) {
                    listings.addAll(cloneListings(roomoramaListings.subList(offset, limit)));
                }              
            }            
            
            if (listings != null && listings.size() > 0) {
                for (Listing listing : listings) {                    
                    populateListingAttributes(listing);
                }
            }            
            response.setResponse(listings);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response; 
    }
    
    @Override
    public ServiceResponse<Boolean> update(Listing listing) {
        ServiceResponse<Boolean> response = new ServiceResponse<Boolean>();
        boolean success = false;
        try {            
            Listing targetListing = null;
            String targetID = listing.getId();            
            List<Listing> records = MockDS.getListings();
            
            if ( !StringUtils.isEmpty(targetID) && records != null && records.size() > 0) {                
                //CX: find record
                for (Listing record : records) {
                    if (StringUtils.equalsIgnoreCase(record.getId(), targetID)) {
                        targetListing = record;
                        break;
                    }
                }                
                //CX: update dabase record
                if (targetListing != null) {
                    targetListing.setLeaseLongTerm(listing.isLeaseLongTerm());
                    targetListing.setLeaseShortTerm(listing.isLeaseShortTerm());

                    targetListing.setLongMonthRate(listing.getLongMonthRate());            
                    targetListing.setShortDayRate(listing.getShortDayRate());
                    targetListing.setShortWeekRate(listing.getShortWeekRate());
                    targetListing.setShortMonthRate(listing.getShortMonthRate());
            
                    targetListing.setPropertyTypeID(listing.getPropertyTypeID());
                    targetListing.setStatusTypeID(listing.getStatusTypeID());
                    targetListing.setPosterTypeID(listing.getPosterTypeID());
                    targetListing.setFurnishTypeID(listing.getFurnishTypeID());
                    
                    targetListing.setTitle( trimTitle(listing.getTitle()) );
                    targetListing.setDescription(cleanHtmlFragment(listing.getDescription(), "id|style"));
                    targetListing.setNotes(listing.getNotes());

                    targetListing.setAddress(listing.getAddress());
                    targetListing.setCountry(listing.getCountry());
                    targetListing.setRegion(listing.getRegion());
                    targetListing.setCity(listing.getCity());
                    targetListing.setBarangay(listing.getBarangay());
                    targetListing.setStreet(listing.getStreet());
                    targetListing.setStructure(listing.getStructure());
                    targetListing.setNumber(listing.getNumber());
                    targetListing.setFloor(listing.getFloor());
                    targetListing.setZip(listing.getZip());
            
                    targetListing.setLat(listing.getLat());
                    targetListing.setLng(listing.getLng());

                    targetListing.setAvailabilityDate(listing.getAvailabilityDate());
                    targetListing.setSqArea(listing.getSqArea());
                                        
                    targetListing.setNumBedrooms(listing.getNumBedrooms());
                    targetListing.setNumBathrooms(listing.getNumBathrooms());

                    targetListing.setLeaseStartDate(listing.getLeaseStartDate());
                    targetListing.setLeaseEndDate(listing.getLeaseEndDate());
                
                    targetListing.setVerified(listing.isVerified());
                    targetListing.setAvailable(listing.isAvailable());
                    targetListing.setPosted(listing.isPosted());
                                        
                    //targetListing.setPostDate(listing.getPostDate());
                    targetListing.setExpiryDate(listing.getExpiryDate());
                            
                    targetListing.setPhotoIDs(listing.getPhotoIDs());                    
                    
                    targetListing.setPlaceIDs(listing.getPlaceIDs());
                    targetListing.setAmenityIDs(listing.getAmenityIDs());
                    
                    targetListing.setCompanyIDs(listing.getCompanyIDs());
                    targetListing.setContactPersonIDs(listing.getContactPersonIDs());
                    
                    targetListing.setCreatorID(listing.getCreatorID());
                    
                    targetListing.setDateModified(new Date());     
                    targetListing.setActive(listing.isActive());
                    
                    //CX: sensitive
                    if (listing.getDateCreated() != null) {                        
                        targetListing.setDateCreated(listing.getDateCreated());
                    }
                    
                    success = true;
                }                
            }            
            response.setResponse(success);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response; 
    }

    @Override
    public ServiceResponse<Boolean> delete(String id) {
        ServiceResponse<Boolean> response = new ServiceResponse<Boolean>();
        boolean success = false;
        try {            
            List<Listing> records = MockDS.getListings();
            
            if (records != null && records.size() > 0) {
                
                for (int i = 0; i < records.size(); i++) {
                    Listing record = records.get(i);
                    
                    if (StringUtils.equalsIgnoreCase(record.getId(), id)) {
                        records.remove(i);
                        success = true;
                        break;
                    }
                }
            }            
            response.setResponse(success);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response; 
    }
    
    @Override
    public ServiceResponse<Boolean> verify(String id, boolean verified) {
        ServiceResponse<Boolean> response = new ServiceResponse<Boolean>();
        boolean success = false;
        try {            
            ServiceResponse<Listing> sr1 = this.read(id);
            Listing listing = sr1.getResponse();
            
            if (listing != null) {
                listing.setVerified(verified);
                ServiceResponse<Boolean> sr2 = this.update(listing);
                success = true;
            }            
            response.setResponse(success);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response; 
    }

    @Override
    public ServiceResponse<List<Listing>> readAllVerified(int offset, int limit, boolean verified) {
        ServiceResponse<List<Listing>> response = new ServiceResponse<List<Listing>>();
        List<Listing> listings = new ArrayList<Listing>();
        try {            
            List<Listing> records = MockDS.getListings();
            
            //CX: filter verified
            
            
            if (records != null && records.size() > 0) {
                
                List<Listing> cloneRecords = cloneListings(records);
                List<Listing> verifiedRecords = new ArrayList<Listing>();
                for (Listing clone : cloneRecords) {
                    if (clone.isVerified() == verified) {
                        verifiedRecords.add(clone);
                    }
                }
                
                if (offset == 0 && limit == 0) {
                    listings.addAll(cloneListings(verifiedRecords));
                }
                else if (offset < verifiedRecords.size() && limit < verifiedRecords.size()) {
                    listings.addAll(cloneListings(verifiedRecords.subList(offset, limit)));
                }              
            }            
            
            if (listings != null && listings.size() > 0) {
                for (Listing listing : listings) {                    
                    populateListingAttributes(listing);
                }
            }            
            response.setResponse(listings);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response; 
    }
    
    @Override
    public ServiceResponse<List<Listing>> readAllPosted(int offset, int limit, boolean posted) {
        ServiceResponse<List<Listing>> response = new ServiceResponse<List<Listing>>();
        List<Listing> listings = new ArrayList<Listing>();
        try {            
            List<Listing> records = MockDS.getListings();
            
            //CX: filter posted            
            
            if (records != null && records.size() > 0) {
                
                List<Listing> cloneRecords = cloneListings(records);
                List<Listing> verifiedRecords = new ArrayList<Listing>();
                for (Listing clone : cloneRecords) {
                    if (clone.isPosted() == posted) {
                        verifiedRecords.add(clone);
                    }
                }
                
                if (offset == 0 && limit == 0) {
                    listings.addAll(cloneListings(verifiedRecords));
                }
                else if (offset < verifiedRecords.size() && limit < verifiedRecords.size()) {
                    listings.addAll(cloneListings(verifiedRecords.subList(offset, limit)));
                }              
            }            
            
            if (listings != null && listings.size() > 0) {
                for (Listing listing : listings) {                    
                    populateListingAttributes(listing);
                }
            }            
            response.setResponse(listings);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response; 
    }
        
    //CX: leaseTerm 1 - Long Term, leaseTerm 2 - shortTerm
    @Override
    public ServiceResponse<List<Listing>> readAllPosted(int offset, int limit, boolean posted, int leaseTerm) {
        ServiceResponse<List<Listing>> response = new ServiceResponse<List<Listing>>();
        List<Listing> listings = new ArrayList<Listing>();
        try {            
            List<Listing> records = MockDS.getListings();
            
            //CX: filter posted     
            
            if (records != null && records.size() > 0) {
                
                List<Listing> cloneRecords = cloneListings(records);
                List<Listing> postedRecords = new ArrayList<Listing>();
                
                for (Listing clone : cloneRecords) {
                    if (clone.isPosted() == posted) {
                        if (leaseTerm == 1 && clone.isLeaseLongTerm()) {
                            postedRecords.add(clone);                            
                        }
                        else if (leaseTerm == 2 && clone.isLeaseShortTerm()) {
                            postedRecords.add(clone); 
                        }
                    }
                }
                                              
                if (offset == 0 && limit == 0) {
                    listings.addAll(cloneListings(postedRecords));
                }
                else if (offset < postedRecords.size() && limit < postedRecords.size()) {
                    listings.addAll(cloneListings(postedRecords.subList(offset, limit)));
                }              
            }            
            
            if (listings != null && listings.size() > 0) {
                for (Listing listing : listings) {                    
                    populateListingAttributes(listing);
                }
            }            
                        
            response.setResponse(listings);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response;
    }
    
    private void populateListingAttributes(Listing listing) {
        if (listing != null) {
            //CXL build display titles
            listing.setDisplayTitle(buildDisplayTitle(listing));
            listing.setUrlTitle(StringUtils.replaceChars(listing.getDisplayTitle(), " ", "-"));
            listing.setDisplayDescription(buildDisplayDescription(listing));
            listing.setDisplayShortDescription(buildDisplayShortDescription(listing));
            
            //CX: build address views
            listing.setAddress(buildAddress(listing));
            listing.setShortAddress(buildShortAddress(listing));
            listing.setCity(buildDisplayCity(listing));
            
            //CX: set rates
            if (StringUtils.isEmpty(listing.getLongMonthRate())) { 
                listing.setLongMonthRate("0.0");
            }
            if (StringUtils.isEmpty(listing.getShortMonthRate())) { 
                listing.setShortMonthRate("0.0");
            }
            if (StringUtils.isEmpty(listing.getShortWeekRate())) { 
                listing.setShortWeekRate("0.0");
            }
            if (StringUtils.isEmpty(listing.getShortDayRate())) { 
                listing.setShortDayRate("0.0");
            }
            
            //CX: populate property type
            listing.setPropertyType(KPropertyTypes.getPropertyType(listing.getPropertyTypeID()));
            
            //CX: populate status type
            listing.setStatusType(KStatusTypes.getStatusType(listing.getStatusTypeID()));
            
            //CX: populate poster type
            listing.setPosterType(KPosterTypes.getPosterType(listing.getPosterTypeID()));
            
            //CX: populate furnish type
            listing.setFurnishType(KFurnishTypes.getFurnishType(listing.getFurnishTypeID()));
                        
            //CX: populate places
            listing.getPlaces().clear();                
            if (listing.getPlaceIDs() != null && listing.getPlaceIDs().size() > 0) {
                ServiceResponse<Place> sr1 = null;

                for (String placeID : listing.getPlaceIDs()) {
                    //sr1 = this.placeService.read(placeID);
                    sr1 = this.placeService.readShallow(placeID);

                    if (sr1.isSuccessful() && sr1.getResponse() != null) {
                        listing.getPlaces().add(sr1.getResponse());
                        
                        //CX: hack to populate community
                        Place place = sr1.getResponse();
                        if ( StringUtils.equals(place.getPlaceTypeID(), KPlaceTypeIDs.BUILDING) ||
                             StringUtils.equals(place.getPlaceTypeID(), KPlaceTypeIDs.VILLAGE)) {
                            listing.setCommunity(place);
                        }
                    }
                }                    
            }                
            //CX: populate amenities
            listing.getAmenities().clear();                
            if (listing.getAmenityIDs() != null && listing.getAmenityIDs().size() > 0) {
                ServiceResponse<Amenity> sr2 = null;

                for (String amenityID : listing.getAmenityIDs()) {
                    sr2 = this.amenityService.read(amenityID);

                    if (sr2.isSuccessful() && sr2.getResponse() != null) {
                        listing.getAmenities().add(sr2.getResponse());
                    }
                }                    
            }                
            //CX: populate photos
            listing.getPhotos().clear();                
            if (listing.getPhotoIDs() != null && listing.getPhotoIDs().size() > 0) {
                ServiceResponse<Photo> sr2 = null;

                for (String photoID : listing.getPhotoIDs()) {
                    sr2 = this.photoService.read(photoID);                        
                    if (sr2.isSuccessful() && sr2.getResponse() != null) {
                        listing.getPhotos().add(sr2.getResponse());
                    }
                }                    
            }
            //CX: populate contact persons
            if (listing.getContactPersonIDs() != null && listing.getContactPersonIDs().size() > 0) {
                ServiceResponse<User> sr3 = null;

                for (String userID : listing.getContactPersonIDs()) {
                    sr3 = this.userService.read(userID);
                    if (sr3.isSuccessful() && sr3.getResponse() != null) {
                        listing.getContactPersons().add(sr3.getResponse());
                    }
                }        
            }
            //CX: populate primary            
            if (listing.getPhotos() != null && listing.getPhotos().size() > 0) {
                listing.setPrimaryPhoto(listing.getPhotos().get(0));
            }
            //CX: populate creator
            if (!StringUtils.isEmpty(listing.getCreatorID())) {
                ServiceResponse<User> sr4 = userService.read(listing.getCreatorID());
                if (sr4.isSuccessful() && sr4.getResponse() != null) {
                    listing.setCreator(sr4.getResponse());
                }
            }
        }            
    }
    
    private String buildDisplayTitle(Listing listing) {
        String displayTitle = "";
        
        if (!StringUtils.isEmpty(listing.getTitle())) {
            String tempTitle = listing.getTitle();            
            tempTitle = tempTitle.replaceAll("[^\\dA-Za-z0-9 ]", "");
            
            if (tempTitle.trim().length() > 64) {
                displayTitle = tempTitle.trim().substring(0, 64);
            }
            else {
                displayTitle = tempTitle.trim();
            }
        }
        return displayTitle;
    }
    
    private String cleanHtmlFragment(String htmlFragment, String attributesToRemove) {
        String fragment = "";
        if (!StringUtils.isEmpty(htmlFragment)) {
            fragment = htmlFragment.replaceAll("\\s+(?:" + attributesToRemove + ")\\s*=\\s*\"[^\"]*\"","");
        }
        return fragment;    
    }
    
    private String buildDisplayDescription(Listing listing) {
        String displayDescription = "";
        
        if (!StringUtils.isEmpty(listing.getDescription())) {
            String tempDescription = listing.getDescription();            
            tempDescription = tempDescription.replaceAll("[^\\dA-Za-z0-9 ]", "");
            
            
            tempDescription = cleanHtmlFragment(listing.getDescription(), "id|style");
    
            
            if (tempDescription.trim().length() > 2000) {
                //CX: remove max chars for now
                //descriptionTitle = tempDescription.trim().substring(0, 2000);
                displayDescription = tempDescription.trim();
            }
            else {
                displayDescription = tempDescription.trim();
            }
        }
        return displayDescription;
    }
    
    private String buildDisplayShortDescription(Listing listing) {
        String displayDescription = "";
        try {            
            if (!StringUtils.isEmpty(listing.getDescription())) {
                String tempDescription = listing.getDescription();            
                tempDescription = Jsoup.parse(tempDescription).text();
                
                if (tempDescription.trim().length() > 200) {
                    //CX: remove max chars for now
                    displayDescription = tempDescription.trim().substring(0, 200);
                }
                else {
                    displayDescription = tempDescription.trim();
                }
            }
        } catch (Exception ex) {
            
        }
        return displayDescription;
    }
    
    private String buildAddress(Listing listing) {
        StringBuilder sb = new StringBuilder(""); 
        if (!StringUtils.isEmpty(listing.getPropertyTypeID())) {
            if (listing.getPropertyTypeID().equals(KPropertyTypeIDs.CONDOMINIUM)) {
                if (!StringUtils.isEmpty(listing.getNumber())) {
                    sb.append( listing.getNumber() ).append(" ");
                }        
                if (!StringUtils.isEmpty(listing.getStructure())) {
                    sb.append( listing.getStructure() ).append(", ");
                }    
                if (!StringUtils.isEmpty(listing.getStreet())) {
                    sb.append( listing.getStreet() ).append(", ");
                }     
                if (!StringUtils.isEmpty(listing.getBarangay())) {
                    sb.append( listing.getBarangay() ).append(", ");
                }    
                if (!StringUtils.isEmpty(listing.getCity())) {
                    sb.append( listing.getCity() ).append(" ");
                }
                if (!StringUtils.isEmpty(listing.getZip())) {
                    sb.append( listing.getZip() );
                }            
            }
            else {
                if (!StringUtils.isEmpty(listing.getNumber())) {
                    sb.append( listing.getNumber() ).append(" ");
                }        
                if (!StringUtils.isEmpty(listing.getStreet())) {
                    sb.append( listing.getStreet() ).append(", ");
                }     
                if (!StringUtils.isEmpty(listing.getStructure())) {
                    sb.append( listing.getStructure() ).append(", ");
                }    
                if (!StringUtils.isEmpty(listing.getBarangay())) {
                    sb.append( listing.getBarangay() ).append(", ");
                }    
                if (!StringUtils.isEmpty(listing.getCity())) {
                    sb.append( listing.getCity() ).append(" ");
                }
                if (!StringUtils.isEmpty(listing.getZip())) {
                    sb.append( listing.getZip() );
                }            
            }            
        }
        return sb.toString();
    }
        
    private String buildShortAddress(Listing listing) {
        StringBuilder sb = new StringBuilder("");        
        if (!StringUtils.isEmpty(listing.getBarangay())) {
            sb.append( listing.getBarangay() ).append(", ");
        }    
        if (!StringUtils.isEmpty(listing.getCity())) {
            sb.append( listing.getCity() );
        }
        return sb.toString();
    }
    
    private String buildDisplayCity(Listing listing) {
        String displayCity = "";    
        try {
            if (!StringUtils.isEmpty(listing.getCity())) {
                displayCity = listing.getCity();
                displayCity = displayCity.replaceAll("city", "");
                displayCity = displayCity.replaceAll("City", "");
                displayCity = displayCity.trim();
            }             
        } catch (Exception ex) {
            
        }   
        return displayCity;
    }
        
    private List<Listing> cloneListings(List<Listing> listings) {
        List<Listing> cloneList = new ArrayList<Listing>(0);
        for (Listing listing : listings) {
            cloneList.add(cloneListing(listing));
        }
        return cloneList;
    }
    
    private Listing cloneListing(Listing listing) {
        return cloner.deepClone(listing);
    }
    
    /*
    @Override
    public ServiceResponse<String> addPosting(String userID, String title, String desc, String address, String lat, String lng) {
        ServiceResponse<String> response = new ServiceResponse<String>();
        String id = null;
        
        try {            
            Listing p = new Listing();
            id = UUID.randomUUID().toString();
            
            p.setId(id);
            p.setTitle(title);
            p.setDescription(desc);
            p.setAddress(address);
            p.setLat(lat);
            p.setLng(lng);
            
            p.setActive(true);
            p.setDateCreated(new Date());
            
            //CX: add user
            ServiceResponse<User> sr = userService.getUser(userID);
            if (sr.isSuccessful() && sr.getResponse() != null) {
                p.setCreatorID(sr.getResponse().getId());
                p.setCreator(sr.getResponse());
            }
            
            MockDS.getPostings().add(p);
            
            response.setResponse(id);
            response.setSuccessful(true);
            
        } catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response;      
    }
    
    @Override
    public ServiceResponse<String> addPosting(String userID, String title, String desc, String address, String lat, String lng, List<String> placeIDs, List<String> retypeL1IDs, List<String> retypeL2IDs) {
        ServiceResponse<String> response = new ServiceResponse<String>();
        String id = null;
        
        try {            
            Listing p = new Listing();
            id = UUID.randomUUID().toString();
            
            p.setId(id);
            p.setTitle(title);
            p.setDescription(desc);
            p.setAddress(address);
            p.setLat(lat);
            p.setLng(lng);
            
            if (placeIDs != null && placeIDs.size() > 0) {
                for (String placeID : placeIDs) {
                    ServiceResponse<Place> sr = placeService.getPlace(placeID);
                    p.getPlaces().add(sr.getResponse());
                }
            }
            
            if (retypeL1IDs != null && retypeL1IDs.size() > 0) {
                for (String retypeL1ID : retypeL1IDs) {
                    ServiceResponse<RETypeL1> sr = retypeService.getRETypeL1(retypeL1ID);
                    p.getReTypesL1().add(sr.getResponse());
                }
            }
            
            p.setActive(true);
            p.setDateCreated(new Date());
            
            //CX: add user
            ServiceResponse<User> sr = userService.getUser(userID);
            if (sr.isSuccessful() && sr.getResponse() != null) {
                p.setCreatorID(sr.getResponse().getId());
                p.setCreator(sr.getResponse());
            }
            
            MockDS.getPostings().add(p);
            
            response.setResponse(id);
            response.setSuccessful(true);
            
        } catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response;      
    }
    
    @Override
    public ServiceResponse<String> addPosting(String userID, String title, String desc, String address, String lat, String lng, List<String> placeIDs, List<String> retypeL1IDs, List<String> retypeL2IDs, String price, String sqArea, int numBedrooms, int numBathrooms, boolean forSale, boolean forRent, boolean forClosed, boolean forOwn, String notes, List<String> images) {
        ServiceResponse<String> response = new ServiceResponse<String>();
        String id = null;
        
        try {            
            Listing p = new Listing();
            id = UUID.randomUUID().toString();
            
            p.setId(id);
            p.setTitle(title);
            p.setDescription(desc);
            p.setAddress(address);
            p.setLat(lat);
            p.setLng(lng);
            
            if (placeIDs != null && placeIDs.size() > 0) {
                for (String placeID : placeIDs) {
                    ServiceResponse<Place> sr = placeService.getPlace(placeID);
                    p.getPlaces().add(sr.getResponse());
                }
            }
            
            if (retypeL1IDs != null && retypeL1IDs.size() > 0) {
                for (String retypeL1ID : retypeL1IDs) {
                    ServiceResponse<RETypeL1> sr = retypeService.getRETypeL1(retypeL1ID);
                    p.getReTypesL1().add(sr.getResponse());
                }
            }
                        
            p.setRate(price);
            p.setSqArea(sqArea);
            p.setNumBathrooms(numBathrooms);
            p.setNumBedrooms(numBedrooms);
                        
            p.setNotes(notes);
            
            if (images != null && images.size() > 0) {
                for (String image : images) {
                    p.getImages().add( new Photo(UUID.randomUUID().toString(), image) );
                }
            }
            
            //CX: temp- set first image as primary
            if (p.getImages() != null && p.getImages().size() > 0) {
               p.setPrimaryImage( p.getImages().get(0) );
            }
            
            p.setActive(true);
            p.setDateCreated(new Date());
            
            //CX: add user
            ServiceResponse<User> sr = userService.getUser(userID);
            if (sr.isSuccessful() && sr.getResponse() != null) {
                p.setCreatorID(sr.getResponse().getId());
                p.setCreator(sr.getResponse());
            }
            
            MockDS.getPostings().add(p);
            
            response.setResponse(id);
            response.setSuccessful(true);
            
        } catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response;      
    }
        
    @Override
    public ServiceResponse<String> addPostingImages(String id, List<String> images) {
        ServiceResponse<String> response = new ServiceResponse<String>();
        
        try {                        
            Listing p = this.getPosting(id).getResponse();    
            
            if (images != null && images.size() > 0) {
                for (String image : images) {
                    p.getImages().add( new Photo(UUID.randomUUID().toString(), image) );
                }
            }            
            
            //CX: temp- set first image as primary
            if (p.getImages() != null && p.getImages().size() > 0) {
               p.setPrimaryImage( p.getImages().get(0) );
            }
            
            response.setResponse(id);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response;      
    }
    
    public ServiceResponse<String> updatePosting(String id, String title, String desc, String address, String lat, String lng, List<String> placeIDs, List<String> retypeL1IDs, List<String> retypeL2IDs) {
        ServiceResponse<String> response = new ServiceResponse<String>();
        
        try {            
            Listing p = this.getPosting(id).getResponse();
            
            if (p != null) {    
                p.setTitle(title);
                p.setDescription(desc);
                p.setAddress(address);
                p.setLat(lat);
                p.setLng(lng);

                p.getPlaces().clear();
                if (placeIDs != null && placeIDs.size() > 0) {
                    for (String placeID : placeIDs) {
                        ServiceResponse<Place> sr = placeService.getPlace(placeID);
                        p.getPlaces().add(sr.getResponse());
                    }
                }

                p.getReTypesL1().clear();
                if (retypeL1IDs != null && retypeL1IDs.size() > 0) {
                    for (String retypeL1ID : retypeL1IDs) {
                        ServiceResponse<RETypeL1> sr = retypeService.getRETypeL1(retypeL1ID);
                        p.getReTypesL1().add(sr.getResponse());
                    }
                }

                p.setActive(true);
                p.setDateCreated(new Date());

                response.setResponse(id);
                response.setSuccessful(true);                
            }
        } catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response;
    }
         
    @Override
    public ServiceResponse<List<Listing>> getPostingAll() {
        ServiceResponse<List<Listing>> response = new ServiceResponse<List<Listing>>();
        List<Listing> postings = new ArrayList<Listing>();
        try {
            List<Listing> records = MockDS.getPostings();
            if (records != null && records.size() > 0) {
                for (Listing record : records) {
                    if (record.isActive()) {
                        postings.add(record);
                    }
                }
            }
            response.setResponse(postings);
            response.setSuccessful(true);            
        } catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response; 
    }

    @Override
    public ServiceResponse<Listing> getPosting(String id) {
        ServiceResponse<Listing> response = new ServiceResponse<Listing>();
        Listing posting = null;
        try {
            List<Listing> postings = MockDS.getPostings();
            if (postings != null && postings.size() > 0) {
                for (Listing record : postings) {
                    if (StringUtils.equalsIgnoreCase(record.getId(), id)) {
                        posting = record;
                        break;
                    }
                }
            }
            response.setResponse(posting);
            response.setSuccessful(true);            
        } catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response; 
    }

    @Override
    public ServiceResponse<List<Listing>> getPostingAll(QueryFilter filter) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public ServiceResponse<Boolean> deactivatePosting(String id) {
        ServiceResponse<Boolean> response = new ServiceResponse<Boolean>();
        try {
            for (Listing posting : this.getPostingAll().getResponse()) {
                if (StringUtils.equalsIgnoreCase(id, posting.getId())) {
                    posting.setActive(false);
                    break;
                }
            }
            response.setResponse(true);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response; 
    }

    @Override
    public ServiceResponse<List<Listing>> getUserPostings(String userID) {
        ServiceResponse<List<Listing>> response = new ServiceResponse<List<Listing>>();
        List<Listing> postings = new ArrayList<Listing>();
        try {
            List<Listing> records = MockDS.getPostings();
            if (records != null && records.size() > 0) {
                for (Listing record : records) {
                    if ( record.getCreator() != null &&
                         StringUtils.equals(userID, record.getCreator().getId()) &&
                        record.isActive() ) {
                        postings.add(record);
                    }
                }
            }
            response.setResponse(postings);
            response.setSuccessful(true);            
        } catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response; 
    }

    @Override
    public ServiceResponse<List<Listing>> getPlacePostings(String placeID) {
        ServiceResponse<List<Listing>> response = new ServiceResponse<List<Listing>>();
        List<Listing> postings = new ArrayList<Listing>();
        try {
            ServiceResponse<Place> sr = placeService.getPlace(placeID);
            
            if (sr.getResponse() != null) {
                Place pl = sr.getResponse();                
                List<Listing> records = MockDS.getPostings();
                
                if (records != null && records.size() > 0) {
                    for (Listing record : records) {     
                        
                        if (record.isActive()) {
                            List<Place> places = record.getPlaces();
                            
                            if (places != null && places.size() > 0) {
                                for (Place place : places) {
                                    if ( StringUtils.equals(placeID, place.getId())) {
                                        postings.add(record);
                                    }
                                }
                            }                            
                        }                        
                    }
                }
            }            
            
            response.setResponse(postings);
            response.setSuccessful(true);            
        } catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response; 
    }

    @Override
    public ServiceResponse<Boolean> removePostingImage(String postingID, String imageID) {
        ServiceResponse<Boolean> response = new ServiceResponse<Boolean>();
        List<Listing> postings = new ArrayList<Listing>();
        try {
            ServiceResponse<Listing> sr = this.getPosting(postingID);
            Listing posting = sr.getResponse();
            List<Photo> filtered = new ArrayList<Photo>();
            
            if (posting != null) {
                if (posting.getImages() != null && posting.getImages().size() > 0) {
                    for (Photo image : posting.getImages()) {
                        if (!StringUtils.equalsIgnoreCase(image.getId(), imageID)) {
                            filtered.add(image);
                        }
                    }
                }
                
                posting.getImages().clear();
                posting.getImages().addAll(filtered);
                
                //CX: temp- set first image as primary
                if (posting.getImages() != null && posting.getImages().size() > 0) {
                   posting.setPrimaryImage( posting.getImages().get(0) );
                }            
            }
            
            response.setResponse(true);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response; 
    }
    */

    @Override
    public ServiceResponse<List<Listing>> readUserListings(String userID, int offset, int limit) {
        ServiceResponse<List<Listing>> response = new ServiceResponse<List<Listing>>();
        List<Listing> listings = new ArrayList<Listing>();
        try {            
            List<Listing> records = MockDS.getListings();
            if (records != null && records.size() > 0) {
                if (offset == 0 && limit == 0) {
                    listings.addAll(cloneListings(records));
                }
                else if (offset < records.size() && limit < records.size()) {
                    listings.addAll(cloneListings(records.subList(offset, limit)));
                }              
            }            
            
            //CX: filter to only listings of target user
            if (!StringUtils.isEmpty(userID)) {
                List<Listing> tempList = new ArrayList<Listing>();
                
                if (listings != null && listings.size() > 0 ) {
                    for (Listing record : listings) {
                        if (StringUtils.equalsIgnoreCase(userID, record.getCreatorID())) {
                            tempList.add(record);
                        }
                    }                    
                }
                
                listings.clear();
                if (tempList != null && tempList.size() > 0) {
                    listings.addAll(tempList);
                }
            }
            
            //CX: fill up listings info
            if (listings != null && listings.size() > 0) {
                for (Listing listing : listings) {                    
                    populateListingAttributes(listing);
                }
            }            
            response.setResponse(listings);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response; 
    }

    @Override
    public ServiceResponse<List<Listing>> readPlaceListings(String placeID, int offset, int limit) {
        ServiceResponse<List<Listing>> response = new ServiceResponse<List<Listing>>();
        List<Listing> placeListings = new ArrayList<Listing>();
        List<Listing> listings = new ArrayList<Listing>();
        
        try {         
            ServiceResponse<List<Listing>> sr1 = this.readAll(0, 0);
            List<Listing> records = sr1.getResponse();
                           
            //CX: filter to only listings of target place
            if (records != null && records.size() > 0 && !StringUtils.isEmpty(placeID)) {
                List<Listing> tempList = new ArrayList<Listing>();
                
                if (records != null && records.size() > 0 ) {
                    for (Listing record : records) {
                        List<Place> listingPlaces = record.getPlaces();
                        
                        if (listingPlaces != null && listingPlaces.size() > 0) {
                            
                            for (Place place : listingPlaces) {
                                
                                if (StringUtils.equalsIgnoreCase(placeID, place.getId())) {
                                    tempList.add(record);
                                }
                            }                            
                        }
                    }                    
                }
                
                listings.clear();
                if (tempList != null && tempList.size() > 0) {
                    listings.addAll(tempList);
                }
            }            
            
            //CX: filter offset and limit
            if (listings != null && listings.size() > 0) {
                if (offset == 0 && limit == 0) {
                    placeListings.addAll(cloneListings(listings));
                }
                else if (offset < listings.size() && limit < listings.size()) {
                    placeListings.addAll(cloneListings(listings.subList(offset, limit)));
                }       
                else {
                    placeListings.addAll(cloneListings(listings));                    
                }            
            }        
            
            //CX: fill up listings info
            if (placeListings != null && placeListings.size() > 0) {
                for (Listing listing : placeListings) {                    
                    populateListingAttributes(listing);
                }
                Collections.sort(placeListings, new ListingComparator());
            }            
            response.setResponse(placeListings);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response; 
    }

    
    @Override
    public ServiceResponse<List<Listing>> readPlaceListings(String placeID, int offset, int limit, int leaseTerm) {
        ServiceResponse<List<Listing>> response = new ServiceResponse<List<Listing>>();
        List<Listing> placeListings = new ArrayList<Listing>();
        List<Listing> listings = new ArrayList<Listing>();
        
        try {         
            ServiceResponse<List<Listing>> sr1 = this.readAll(0, 0);
            List<Listing> records = sr1.getResponse();
                           
            //CX: filter to only listings of target place
            if (records != null && records.size() > 0 && !StringUtils.isEmpty(placeID)) {
                List<Listing> tempList = new ArrayList<Listing>();
                
                if (records != null && records.size() > 0 ) {
                    for (Listing record : records) {
                        List<Place> listingPlaces = record.getPlaces();
                        
                        if (listingPlaces != null && listingPlaces.size() > 0) {
                            
                            for (Place place : listingPlaces) {
                                
                                if (StringUtils.equalsIgnoreCase(placeID, place.getId())) {
                                    tempList.add(record);
                                }
                            }                            
                        }
                    }                    
                }
                
                listings.clear();
                if (tempList != null && tempList.size() > 0) {
                    for (Listing listing : tempList) {
                        if (leaseTerm == 1 && listing.isLeaseLongTerm()) {
                            listings.add(listing);                            
                        }
                        else if (leaseTerm == 2 && listing.isLeaseShortTerm()) {
                            listings.add(listing); 
                        }
                    }
                }
            }            
            
            //CX: filter offset and limit
            if (listings != null && listings.size() > 0) {
                if (offset == 0 && limit == 0) {
                    placeListings.addAll(cloneListings(listings));
                }
                else if (offset < listings.size() && limit < listings.size()) {
                    placeListings.addAll(cloneListings(listings.subList(offset, limit)));
                }       
                else {
                    placeListings.addAll(cloneListings(listings));                    
                }            
            }        
            
            //CX: fill up listings info
            if (placeListings != null && placeListings.size() > 0) {
                for (Listing listing : placeListings) {                    
                    populateListingAttributes(listing);
                }
                Collections.sort(placeListings, new ListingComparator());
            }            
            response.setResponse(placeListings);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response; 
    }
    
    @Override
    public ServiceResponse<List<Listing>> readPlaceListingsRoomorama(String placeID, int offset, int limit) {
        ServiceResponse<List<Listing>> response = new ServiceResponse<List<Listing>>();
        List<Listing> placeListings = new ArrayList<Listing>();
        List<Listing> listings = new ArrayList<Listing>();
        
        try {         
            ServiceResponse<List<Listing>> sr1 = this.readAllRoomorama(0, 0);
            List<Listing> records = sr1.getResponse();
                           
            //CX: filter to only listings of target place
            if (records != null && records.size() > 0 && !StringUtils.isEmpty(placeID)) {
                List<Listing> tempList = new ArrayList<Listing>();
                
                if (records != null && records.size() > 0 ) {
                    for (Listing record : records) {
                        List<Place> listingPlaces = record.getPlaces();
                        
                        if (listingPlaces != null && listingPlaces.size() > 0) {
                            
                            for (Place place : listingPlaces) {
                                
                                if (StringUtils.equalsIgnoreCase(placeID, place.getId())) {
                                    tempList.add(record);
                                }
                            }                            
                        }
                    }                    
                }
                
                listings.clear();
                if (tempList != null && tempList.size() > 0) {
                    listings.addAll(tempList);
                }
            }            
            
            //CX: filter offset and limit
            if (listings != null && listings.size() > 0) {
                if (offset == 0 && limit == 0) {
                    placeListings.addAll(cloneListings(listings));
                }
                else if (offset < listings.size() && limit < listings.size()) {
                    placeListings.addAll(cloneListings(listings.subList(offset, limit)));
                }       
                else {
                    placeListings.addAll(cloneListings(listings));                    
                }            
            }        
            
            //CX: fill up listings info
            if (placeListings != null && placeListings.size() > 0) {
                for (Listing listing : placeListings) {                    
                    populateListingAttributes(listing);
                }
            }            
            response.setResponse(placeListings);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response; 
    }
    
    public static void main (String argv[]) {
        MListingService service = new MListingService();
        Listing listing = new Listing();
        listing.setTitle("\\/\\/!!!{}`:>?:645656#$#%#$^%$#^^%Condo For Rent at West of Ayala Makati 1 Bedroom O TALAGA Fully Furnished TALAGA");
        String displayTitle = service.buildDisplayTitle(listing);
        System.out.println("CX: " + displayTitle);
    }

    @Override
    public ServiceResponse<Boolean> setAvailability(String id, boolean available) {
        ServiceResponse<Boolean> response = new ServiceResponse<Boolean>();
        boolean success = false;
        try {             
            for (Listing record : MockDS.getListings()) {
                if (StringUtils.equals(record.getId(), id)) {
                    record.setAvailable(available);
                }
            }
            success = true;
            response.setResponse(success);
            response.setSuccessful(success);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response;
    }

    @Override
    public ServiceResponse<Boolean> postListing(String id) {
        ServiceResponse<Boolean> response = new ServiceResponse<Boolean>();
        boolean success = false;
        try {             
            for (Listing record : MockDS.getListings()) {
                if (StringUtils.equals(record.getId(), id)) {
                    //CX: set as posted
                    record.setPosted(true);
                    
                    //CX: set post date as well as date created and date modified
                    Date postDate = new Date();
                    record.setPostDate(postDate);
                    record.setDateCreated(postDate);
                    record.setDateModified(postDate);
                    
                    //CX: set expiry date
                    Date expiryDate = null;
                    Calendar c = Calendar.getInstance();
                    c.setTime(new Date()); // Now use today date.
                    c.add(Calendar.DATE, 30); // Adding 30 days
                    expiryDate = c.getTime();
                    record.setExpiryDate(expiryDate);
                }
            }
            success = true;
            response.setResponse(success);
            response.setSuccessful(success);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response;
    }

    @Override
    public ServiceResponse<Boolean> unpostListing(String id) {
        ServiceResponse<Boolean> response = new ServiceResponse<Boolean>();
        boolean success = false;
        try {             
            for (Listing record : MockDS.getListings()) {
                if (StringUtils.equals(record.getId(), id)) {
                    //CX: set as posted
                    record.setPosted(false);
                    
                    //CX: set post 
                    record.setPostDate(null);
                    
                    //CX: set expiry date
                    record.setExpiryDate(null);
                }
            }
            success = true;
            response.setResponse(success);
            response.setSuccessful(success);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response;
    }

    @Override
    public ServiceResponse<Boolean> setPenalized(String id, boolean penalize) {
        ServiceResponse<Boolean> response = new ServiceResponse<Boolean>();
        boolean success = false;
        try {             
            for (Listing record : MockDS.getListings()) {
                if (StringUtils.equals(record.getId(), id)) {
                    //CX: set penalized
                    record.setPenalized(penalize);
                }
            }
            success = true;
            response.setResponse(success);
            response.setSuccessful(success);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response;
    }
        
    @Override
    public ServiceResponse<Boolean> incrementImpressions(String id) {
        ServiceResponse<Boolean> response = new ServiceResponse<Boolean>();
        boolean success = false;
        try {             
            for (Listing record : MockDS.getListings()) {
                if (StringUtils.equals(record.getId(), id)) {
                    //CX: increment impression by 1
                    long impressions = record.getImpressions();
                    record.setImpressions(  impressions += 1 );
                }
            }
            success = true;
            response.setResponse(success);
            response.setSuccessful(success);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response;
    }

    @Override
    public ServiceResponse<Boolean> incrementViews(String id) {
        ServiceResponse<Boolean> response = new ServiceResponse<Boolean>();
        boolean success = false;
        try {             
            for (Listing record : MockDS.getListings()) {
                if (StringUtils.equals(record.getId(), id)) {
                    //CX: increment impression by 1
                    long views = record.getViews();
                    record.setViews( views += 1 );
                }
            }
            success = true;
            response.setResponse(success);
            response.setSuccessful(success);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response;
    }
    
    @Override
    public ServiceResponse<List<Listing>> readRoomoramaListings(int offset, int limit) {
        ServiceResponse<List<Listing>> response = new ServiceResponse<List<Listing>>();
        List<Listing> listings = new ArrayList<Listing>();
        try {            
            List<Listing> records = MockDS.getListings();
            
            //CX: filter posted     
            
            if (records != null && records.size() > 0) {
                
                List<Listing> cloneRecords = cloneListings(records);
                List<Listing> roomoramaRecords = new ArrayList<Listing>();
                
                for (Listing clone : cloneRecords) {
                    if (clone.isRoomoramaListing()) {
                        roomoramaRecords.add(clone);   
                    }
                }
                                              
                if (offset == 0 && limit == 0) {
                    listings.addAll(cloneListings(roomoramaRecords));
                }
                else if (offset < roomoramaRecords.size() && limit < roomoramaRecords.size()) {
                    listings.addAll(cloneListings(roomoramaRecords.subList(offset, limit)));
                }              
            }            
            
            if (listings != null && listings.size() > 0) {
                for (Listing listing : listings) {                    
                    populateListingAttributes(listing);
                }
            }            
            response.setResponse(listings);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response;
    }

    @Override
    public ServiceResponse<List<Listing>> readShortTermListings(int offset, int limit) {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public ServiceResponse<List<Listing>> readLongTermListings(int offset, int limit) {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public ServiceResponse<Boolean> clearShortTermListings() {
        ServiceResponse<Boolean> response = new ServiceResponse<Boolean>();
        boolean success = false;
        try {            
            List<Listing> records = this.cloneListings(MockDS.getListings());            
            if (records != null && records.size() > 0) {
                
                for (int i = 0; i < records.size(); i++) {
                    Listing record = records.get(i);
                    
                    if (record.isLeaseShortTerm()) {
                        this.delete(record.getId());
                    }
                }
            }            
            success = true;
            response.setResponse(success);
            response.setSuccessful(true);             
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response; 
    }

    @Override
    public ServiceResponse<Boolean> clearLongTermListings() {
        ServiceResponse<Boolean> response = new ServiceResponse<Boolean>();
        boolean success = false;
        try {            
            List<Listing> records = this.cloneListings(MockDS.getListings());            
            if (records != null && records.size() > 0) {
                
                for (int i = 0; i < records.size(); i++) {
                    Listing record = records.get(i);
                    
                    if (record.isLeaseLongTerm()) {
                        this.delete(record.getId());
                    }
                }
            }            
            success = true;
            response.setResponse(success);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response; 
    }

    @Override
    public ServiceResponse<Boolean> clearRoomoramaListings() {
        ServiceResponse<Boolean> response = new ServiceResponse<Boolean>();
        boolean success = false;
        try {            
            List<Listing> records = this.cloneListings(MockDS.getListings());            
            if (records != null && records.size() > 0) {
                
                for (int i = 0; i < records.size(); i++) {
                    Listing record = records.get(i);
                    
                    if (record.isRoomoramaListing()) {
                        this.delete(record.getId());
                    }
                }
            }            
            success = true;
            response.setResponse(success);
            response.setSuccessful(true);         
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response; 
    }

    @Override
    public ServiceResponse<List<Listing>> readFiltered(SearchOption searchOption) {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public ServiceResponse<Integer> countFiltered(SearchOption searchOption) {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public ServiceResponse<List<Listing>> readFilteredVerified(SearchOption searchOption) {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public ServiceResponse<Boolean> delete(String listingID, String userID) {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

}
